package com.blank.black.common;

import com.alibaba.fastjson.JSONArray;
import com.blank.black.entity.bo.example.*;
import com.blank.black.entity.pojo.*;
import com.blank.black.enums.*;

import java.util.*;
import java.util.stream.Collectors;

public class BlankUtils {
    public final static String NULL_STR = "@{null}";
    public final static String PRE_NULL_STR = "/" + NULL_STR;

    public static CommonExample config2CommonExample(BlankConfig exampleConfig, Map<String, Object> param) throws Exception {
        if (Objects.isNull(exampleConfig)) {
            return null;
        }
        CommonExample commonExample = new CommonExample();
        // 处理关联关系
        Integer tableIndex = Integer.valueOf(1);
        // 从主表和关联表中获取出表别名，
        //  如果关联的表中有重复的表名，则必须在col,critria、joinrelation中配置表别名
        // 如未配置表别名，则以关联表名中第一次出现的该表名的表别名，作为改配置的表别名，有同名表时不建议缺省表别名，非常容易错乱
        Map<String, String> tableAliasMap = new HashMap<>();
        tableAliasMap.put(exampleConfig.getTableName(),
                BlankUtils.isEmpty(exampleConfig.getTableAlias()) ? "t" + tableIndex++ : exampleConfig.getTableAlias());
        List<ConfigJoin> joinList = exampleConfig.getJoinList();
        for (ConfigJoin configJoin : joinList) {
            if (!tableAliasMap.containsKey(configJoin.getTableName())) {
                tableAliasMap.put(exampleConfig.getTableName(),
                        BlankUtils.isEmpty(configJoin.getTableAlias()) ? "t" + tableIndex++ : configJoin.getTableAlias());
            }
        }

        if (ConfigTypeEnum.SELECT.getCode().equals(exampleConfig.getType()) || ConfigTypeEnum.SELECT_ONE.getCode().equals(exampleConfig.getType())) {
            commonExample.setTableName(exampleConfig.getTableName(), tableAliasMap.get(exampleConfig.getTableName()));
        } else {
            commonExample.setTableName(exampleConfig.getTableName());
        }
        commonExample.setSeparator(LogicEnum.getLogicName(exampleConfig.getSplit()));
        if (!Objects.isNull(param.get("orderByClause")) && !BlankUtils.isEmpty(exampleConfig.getOrderByClause())) {
            List<Map<String, String>> clauseBOList = (List) param.get("orderByClause");
            List<String> list = Arrays.asList(exampleConfig.getOrderByClause().split(","));
            List<String> collect = new ArrayList<>();
            for (Map<String, String> map : clauseBOList) {
                if (list.contains(map.get("name"))) {
                    collect.add(map.get("name") + " " + (BlankUtils.isEmpty(map.get("sort")) ? "" : map.get("sort")));
                }
            }
            if (collect.size() > 0) {
                commonExample.setOrderByClause(String.join(",", collect));
            }
        }
        commonExample.setDistinct(BooleanEnum.TRUE.getCode().equals(exampleConfig.getDistinctFlag()));
        if (BooleanEnum.TRUE.getCode().equals(exampleConfig.getPageFlag())) {
            Integer pageSize = Objects.isNull(param.get("pageSize")) ? exampleConfig.getPageSize() : BlankUtils.getIngeter(param, "pageSize");
            Integer pageNum = Objects.isNull(param.get("pageNum")) ? 1 : BlankUtils.getIngeter(param, "pageNum");
            commonExample.setOffset(pageNum > 0 ? (pageNum - 1) * pageSize : 0);
            commonExample.setLimit(pageSize * (pageNum > 0 ? 1 : 0));
        }
        if (ConfigTypeEnum.SELECT_ONE.getCode().equals(exampleConfig.getType())) {
            commonExample.setOffset(0);
            commonExample.setLimit(1);
        }
        //col
        if (ConfigTypeEnum.SELECT.getCode().equals(exampleConfig.getType()) || ConfigTypeEnum.SELECT_ONE.getCode().equals(exampleConfig.getType())) {
            for (ConfigCol configCol : exampleConfig.getColList()) {
                if (ColTypeEnum.VALUE.getCode().equals(configCol.getColType())) {
                    commonExample.addCol(BlankUtils.config2ExampleCol(configCol, tableAliasMap));
                }
            }
        }

        if (ConfigTypeEnum.UPDATE.getCode().equals(exampleConfig.getType())
                || ConfigTypeEnum.INSERT.getCode().equals(exampleConfig.getType())
        ) {
            List<ExampleUpdate> updateList = new ArrayList<>();
            for (ConfigCol configCol : exampleConfig.getColList()) {
                if (ColTypeEnum.VALUE.getCode().equals(configCol.getColType())) {
                    // 没有传入参数且默认值为空，不更新该字段
                    if (!param.containsKey(configCol.getColAlias()) && BlankUtils.isEmpty(configCol.getDefaultValue())) {
                        continue;
                    }
                    ExampleUpdate update = new ExampleUpdate();
                    update.setKey(configCol.getColName());
                    update.setValue(param.containsKey(configCol.getColAlias()) ? param.get(configCol.getColAlias()) : configCol.getDefaultValue());

                    updateList.add(update);
                }
            }
            commonExample.setUpdateList(updateList);
        }


        // join
        for (ConfigJoin configJoin : joinList) {
            commonExample.addJoin(BlankUtils.config2ExampleJoin(configJoin, tableAliasMap));
        }
        //criteria
        List<ConfigCriteria> criteriaList = exampleConfig.getCriteriaList();
        Map<Integer, List<ConfigCriteria>> groupMap = criteriaList.stream().sorted((item1, item2) -> {
                    if (item1.getGroupId().compareTo(item2.getGroupId()) > 0 && item1.getOrder().compareTo(item1.getOrder()) > 0) {
                        return 1;
                    } else if (item1.getGroupId().compareTo(item2.getGroupId()) == 0 && item1.getOrder().compareTo(item1.getOrder()) == 0) {
                        return 0;
                    }
                    return -1;
                }
        ).collect(Collectors.groupingBy(ConfigCriteria::getGroupId));
        for (Integer item : groupMap.keySet()) {
            CommonExample.Criteria criteria = commonExample.nextGroup();
            for (ConfigCriteria configCriteria : groupMap.get(item)) {
                // 获取参数值
                boolean hasParam = param.containsKey(configCriteria.getColAlias());
                Object value = param.containsKey(configCriteria.getColAlias()) ? param.get(configCriteria.getColAlias()) : null;
                Object dv1 = null, dv2 = null;
                dv1 = configCriteria.getDefaultValue1();
                dv2 = configCriteria.getDefaultValue2();
                if (BooleanEnum.TRUE.getCode().equals(configCriteria.getRequireFlag()) && isNullValue(value,hasParam)) {
                    throw new Exception(configCriteria.getColNameZh() + "不可为空");
                }
                // 不必填，且没有传输该参数 且不强制使用默认值跳过该条件
                if (BooleanEnum.FALSE.getCode().equals(configCriteria.getRequireFlag()) && !hasParam && BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag())) {
                    continue;
                }
                // 不必填，且数据为空 且入参中数据为null时跳过该条件，且不强制使用默认值则跳过该条件
                if (BooleanEnum.FALSE.getCode().equals(configCriteria.getRequireFlag()) &&isNullValue(value,hasParam) && BooleanEnum.FALSE.getCode().equals(configCriteria.getNullFlag())&& BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag())){
                    continue;
                }
                if (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) && !param.containsKey(configCriteria.getColAlias())) {
                    continue;
                }
                // 查询
                if (ConfigTypeEnum.SELECT.getCode().equals(exampleConfig.getType()) || ConfigTypeEnum.SELECT_ONE.getCode().equals(exampleConfig.getType())) {
                    if (ConditionEnum.ISNULL.getCode().equals(configCriteria.getCondition())) {
                        criteria.isNull(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName());
                    } else if (ConditionEnum.ISNOTNULL.getCode().equals(configCriteria.getCondition())) {
                        criteria.isNotNull(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName());
                    } else if (ConditionEnum.EQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.equalTo(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.NOT_EQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.notEqualTo(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.GREATER.getCode().equals(configCriteria.getCondition())) {
                        criteria.greaterThan(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.GREATEREQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.greaterThanOrEqualTo(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.LESS.getCode().equals(configCriteria.getCondition())) {
                        criteria.lessThan(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.LESSEQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.lessThanOrEqualTo(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.LIKE.getCode().equals(configCriteria.getCondition())) {
                        criteria.like(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (String) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1));
                    } else if (ConditionEnum.NOT_LIKE.getCode().equals(configCriteria.getCondition())) {
                        criteria.notLike(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (String) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1));
                    } else if (ConditionEnum.IN.getCode().equals(configCriteria.getCondition())) {
                        criteria.in(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (List<Object>) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : JSONArray.parseArray((String) dv1, String.class)));
                    } else if (ConditionEnum.NOT_IN.getCode().equals(configCriteria.getCondition())) {
                        criteria.notIn(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (List<Object>) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : JSONArray.parseArray((String) dv1, String.class)));
                    } else if (ConditionEnum.BETWEEN.getCode().equals(configCriteria.getCondition())) {
                        criteria.between(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(0) : dv1), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(1) : dv2));
                    } else if (ConditionEnum.NOT_BETWEEN.getCode().equals(configCriteria.getCondition())) {
                        criteria.notBetween(BlankUtils.isEmpty(configCriteria.getTableAlias()) ? tableAliasMap.get(configCriteria.getTableName()) : configCriteria.getTableAlias()
                                , LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(0) : dv1), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(1) : dv2));
                    }
                } else {// 更新或删除
                    if (ConditionEnum.ISNULL.getCode().equals(configCriteria.getCondition())) {
                        criteria.isNull(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName());
                    } else if (ConditionEnum.ISNOTNULL.getCode().equals(configCriteria.getCondition())) {
                        criteria.isNotNull(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName());
                    } else if (ConditionEnum.EQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.equalTo(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.NOT_EQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.notEqualTo(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.GREATER.getCode().equals(configCriteria.getCondition())) {
                        criteria.greaterThan(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.GREATEREQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.greaterThanOrEqualTo(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.LESS.getCode().equals(configCriteria.getCondition())) {
                        criteria.lessThan(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.LESSEQUAL.getCode().equals(configCriteria.getCondition())) {
                        criteria.lessThanOrEqualTo(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1);
                    } else if (ConditionEnum.LIKE.getCode().equals(configCriteria.getCondition())) {
                        criteria.like(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (String) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1));
                    } else if (ConditionEnum.NOT_LIKE.getCode().equals(configCriteria.getCondition())) {
                        criteria.notLike(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (String) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : dv1));
                    } else if (ConditionEnum.IN.getCode().equals(configCriteria.getCondition())) {
                        criteria.in(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (List<Object>) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : JSONArray.parseArray((String) dv1, String.class)));
                        ;
                    } else if (ConditionEnum.NOT_IN.getCode().equals(configCriteria.getCondition())) {
                        criteria.notIn(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (List<Object>) (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? value : JSONArray.parseArray((String) dv1, String.class)));
                        ;
                    } else if (ConditionEnum.BETWEEN.getCode().equals(configCriteria.getCondition())) {
                        criteria.between(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(0) : dv1), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(1) : dv2));
                    } else if (ConditionEnum.NOT_BETWEEN.getCode().equals(configCriteria.getCondition())) {
                        criteria.notBetween(LogicEnum.getLogic(configCriteria.getLogic()), configCriteria.getColName(), (Objects.isNull(dv1) ? ((List) value).get(0) : dv1), (BooleanEnum.FALSE.getCode().equals(configCriteria.getDefaultFlag()) ? ((List) value).get(1) : dv2));
                    }
                }
            }
        }
        return commonExample;


    }

    /**
     * 判断值是否为null
     *
     * @param value
     * @param hasParam
     * @return
     */
    private static boolean isNullValue(Object value, boolean hasParam) {
        if (Objects.isNull(value)) {
            return true;
        } else if (! hasParam) {
            return true;
        } else if (value instanceof List && ((List)value).size() == 0) {
            return true;
        }
        return false;
    }


    public static ExampleCol config2ExampleCol(ConfigCol configCol, Map<String, String> tableAliasMap) {
        ExampleCol exampleCol = new ExampleCol();
        exampleCol.setCol(configCol.getColName());
        exampleCol.setAlias(configCol.getColAlias());
        exampleCol.setTableAlias(BlankUtils.isEmpty(configCol.getTableAlias()) ? tableAliasMap.get(configCol.getTableName()) : configCol.getTableAlias());
        return exampleCol;
    }

    public static ExampleJoin config2ExampleJoin(ConfigJoin configJoin, Map<String, String> tableAliasMap) {
        ExampleJoin exampleJoin = new ExampleJoin();
        exampleJoin.setMode(JoinModeEnum.getModeName(configJoin.getMode()));
        exampleJoin.setTableName(configJoin.getTableName());
        exampleJoin.setAlias(!BlankUtils.isEmpty(configJoin.getTableAlias()) ? configJoin.getTableAlias() : tableAliasMap.get(configJoin.getTableName()));
        List<ConfigJoinRelation> relationList = configJoin.getRelationList();
        List<ExampleJoinRelation> exampleJoinRelationList = relationList.stream().map(item -> {
            ExampleJoinRelation exampleJoinRelation = new ExampleJoinRelation();
            exampleJoinRelation.setLogic(LogicEnum.getLogicName(item.getLogic()));
            exampleJoinRelation.setAlias1(!BlankUtils.isEmpty(item.getTableAlias()) ? item.getTableAlias() : tableAliasMap.get(item.getTableName()));
            exampleJoinRelation.setProperty1(item.getProperty());
            exampleJoinRelation.setAlias2(!BlankUtils.isEmpty(item.getRelationTableAlias()) ? item.getRelationTableAlias() : tableAliasMap.get(item.getRelationTableName()));
            exampleJoinRelation.setProperty2(item.getRelationProperty());
            return exampleJoinRelation;
        }).collect(Collectors.toList());
        exampleJoin.setRelationList(exampleJoinRelationList);
        return exampleJoin;

    }

    public static Integer getIngeter(Map<String, Object> map, String str) {
        if (Objects.isNull(str) || str.length() == 0) {
            return null;
        }
        Object obj = map.get(str);
        if (obj instanceof String) {
            return Integer.valueOf((String) obj);
        } else {
            return (Integer) obj;
        }

    }

    public static boolean isEmpty(String str) {
        if (Objects.isNull(str) || str.length() == 0) {
            return true;
        } else {
            return false;
        }
    }
}
